home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue61 / Contract / AccountExample.pas < prev    next >
Pascal/Delphi Source File  |  2000-08-07  |  4KB  |  159 lines

  1. unit AccountExample;
  2.  
  3. interface
  4.  
  5. uses
  6.     classes;
  7.  
  8. type
  9.  
  10.     { forward declarations }
  11.     TAccountLine = class;
  12.  
  13.   TSimpleAccount = class
  14.   private
  15.     FBalance: Currency;
  16.     FBalanceCalculated: Boolean;
  17.     FLines: TList;
  18.         function CalculateBalance: Currency;
  19.     function GetBalance: Currency;
  20.     function GetAccountLine(Index: Integer): TAccountLine;
  21.     function GetLineCount: Integer;
  22.   protected
  23.       function InternalGetAccountLine(Index: Integer): TAccountLine;
  24.     procedure AssertInvariants; virtual;
  25.     public
  26.       constructor Create;
  27.     destructor Destroy; override;
  28.       function AddLine(const Text: string; Amount: Currency): TAccountLine;
  29.  
  30.     property Balance: Currency read GetBalance;
  31.     property Lines[Index: Integer]: TAccountLine read GetAccountLine;
  32.     property LineCount: Integer read GetLineCount;
  33.   end;
  34.  
  35.     TAccountLine = class
  36.   private
  37.       FText: string;
  38.     FAmount: Currency;
  39.     procedure SetText(const Value: string);
  40.   public
  41.       constructor Create(const AText: string; AAmount: Currency);
  42.       property Text: string read FText write SetText;
  43.     property Amount: Currency read FAmount;
  44.   end;
  45.  
  46. const
  47.     S_PreFailed     = 'Pre-Condition failed: ';
  48.     S_PostFailed  = 'Post-Condition failed: ';
  49.   S_InvFailed        = 'Invariant-Condition failed: ';
  50.  
  51. implementation
  52.  
  53. uses
  54.     contnrs;
  55.  
  56. { TSimpleAccount }
  57.  
  58. function TSimpleAccount.AddLine(const Text: string;
  59.   Amount: Currency): TAccountLine;
  60.  
  61.   procedure AssertPre;
  62.   begin
  63.     AssertInvariants;
  64.       Assert(Length(Text) > 0,S_PreFailed + 'Lenght(Text) must be > 0');
  65.     Assert(Amount<> 0,S_PreFailed + 'Ammount must be <> 0');
  66.   end;
  67.  
  68.   procedure AssertPost;
  69.   begin
  70.     AssertInvariants;
  71.     Assert(Assigned(Result),'Result does not contain a valid AccountLine object');
  72.   end;
  73.  
  74. begin
  75.   AssertPre;
  76.   Result := TAccountLine.Create(Text,Amount);
  77.   FLines.Add(Result);
  78.   { uncomment the next line to fix AssertInvariants failure }
  79.   FBalanceCalculated := False;
  80.   AssertPost;
  81. end;
  82.  
  83. procedure TSimpleAccount.AssertInvariants;
  84. begin
  85.     if FBalanceCalculated then begin
  86.     Assert(FBalance = CalculateBalance,S_InvFailed + 'Balance out of Sync');
  87.     end;
  88. end;
  89.  
  90. function TSimpleAccount.CalculateBalance: Currency;
  91. var
  92.     I: Integer;
  93. begin
  94.     Result := 0;
  95.     for I := 0 to Pred(LineCount) do begin
  96.         Result := Result + InternalGetAccountLine(I).Amount;
  97.   end;
  98. end;
  99.  
  100. constructor TSimpleAccount.Create;
  101. begin
  102.   FLines := TObjectList.Create(True);
  103. end;
  104.  
  105. destructor TSimpleAccount.Destroy;
  106. begin
  107.     FLines.Free;
  108.   inherited Destroy;
  109. end;
  110.  
  111. function TSimpleAccount.GetAccountLine(Index: Integer): TAccountLine;
  112.  
  113.     procedure AssertPre;
  114.   begin
  115.       AssertInvariants;
  116.         Assert((Index > -1) and (Index < LineCount),
  117.            S_PreFailed + 'Index must be > -1 and < Count');
  118.   end;
  119.  
  120. begin
  121.   AssertPre;
  122.     Result := InternalGetAccountLine(Index);
  123. end;
  124.  
  125. function TSimpleAccount.GetBalance: Currency;
  126. begin
  127.     if not FBalanceCalculated then begin
  128.     FBalance := CalculateBalance;
  129.     FBalanceCalculated := True;
  130.   end;
  131.   Result := FBalance;
  132. end;
  133.  
  134. function TSimpleAccount.GetLineCount: Integer;
  135. begin
  136.     Result := FLines.Count;
  137. end;
  138.  
  139. function TSimpleAccount.InternalGetAccountLine(
  140.   Index: Integer): TAccountLine;
  141. begin
  142.     Result := FLines[Index];
  143. end;
  144.  
  145. { TAccountLine }
  146.  
  147. constructor TAccountLine.Create(const AText: string; AAmount: Currency);
  148. begin
  149.   FText := AText;
  150.   FAmount := AAmount;
  151. end;
  152.  
  153. procedure TAccountLine.SetText(const Value: string);
  154. begin
  155.   FText := Value;
  156. end;
  157.  
  158. end.
  159.